home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
ole2book.zip
/
CHAP08.ZIP
/
CHAP08
/
PATRON
/
IDROPTGT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-21
|
13KB
|
518 lines
/*
* IDROPTGT.CPP
*
* Implementation of a DropTarget object for Patron
*
* Copyright (c)1993 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Software Design Engineer
* Microsoft Systems Developer Relations
*
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "patron.h"
/*
* CDropTarget::CDropTarget
* CDropTarget::~CDropTarget
*
* Constructor Parameters:
* pDoc LPCPatronDoc of the window containing us.
*/
CDropTarget::CDropTarget(LPCPatronDoc pDoc)
{
m_cRef=0;
m_pDoc=pDoc;
m_pIDataObject=NULL;
return;
}
CDropTarget::~CDropTarget(void)
{
return;
}
/*
* CDropTarget::QueryInterface
* CDropTarget::AddRef
* CDropTarget::Release
*
* Purpose:
* IUnknown members for CDropTarget object.
*/
STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
*ppv=NULL;
//Any interface on this object is the object pointer.
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDropTarget))
*ppv=(LPVOID)this;
/*
* If we actually assign an interface to ppv we need to AddRef it
* since we're returning a new pointer.
*/
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CDropTarget::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CDropTarget::Release(void)
{
ULONG cRefT;
cRefT=--m_cRef;
if (0L==m_cRef)
delete this;
return cRefT;
}
/*
* CDropTarget::DragEnter
*
* Purpose:
* Indicates that data in a drag operation has been dragged over our
* window that's a potential target. We are to decide if it's something
* we're interested in or not.
*
* Parameters:
* pIDataSource LPDATAOBJECT providing the source data.
* grfKeyState DWORD flags indicating states of keys and mouse buttons.
* pt POINTL coordinates in the client space of the document.
* pdwEffect LPDWORD into which we'll place the appropriate effect
* flag for this point.
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
LPCPages ppg=m_pDoc->m_pPG;
HWND hWnd;
FORMATETC fe;
STGMEDIUM stm;
UINT uRet;
m_fFeedback=FALSE;
m_pIDataObject=NULL;
if (!m_pDoc->FQueryPasteFromData(pIDataSource, &fe, NULL))
{
*pdwEffect=DROPEFFECT_NONE;
return NOERROR;
}
//Check if this is a valid drop point.
uRet=ppg->UTestDroppablePoint(&pt);
ppg->m_uLastTest=uRet;
if (UDROP_NONE==uRet)
*pdwEffect=DROPEFFECT_NONE;
else
{
//Default is move if we can, in fact drop here.
*pdwEffect=DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL)
*pdwEffect=DROPEFFECT_COPY;
}
m_pIDataObject=pIDataSource;
m_pIDataObject->AddRef();
/*
* Determine the size of the data, if we can. The default is
* a small rectangle since we can't easily tell what size something
* will be if we're pulling in a metafile or bitmap. It's not
* a good idea to render it here with ::GetData just to find that out.
* We only know the size if it's our own object in which case a
* ::GetData will be fast.
*/
if (fe.cfFormat==m_pDoc->m_cf)
{
if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
{
LPPATRONOBJECT ppo;
RECT rc;
ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
SetRect(&rc, (int)ppo->szl.cx, -(int)ppo->szl.cy, 0, 0);
RectConvertMappings(&rc, NULL, TRUE);
SETSIZEL(m_szl, rc.left, rc.top);
m_ptPick=ppo->ptlPick;
m_fe=ppo->fe;
GlobalUnlock(stm.hGlobal);
ReleaseStgMedium(&stm);
}
}
else
{
SETSIZEL(m_szl, 30, 30);
m_ptPick.x=0;
m_ptPick.y=0;
m_fe.cfFormat=0;
}
//Bring the document window up front and show what a drop will do.
hWnd=m_pDoc->Window();
BringWindowToTop(hWnd);
UpdateWindow(hWnd);
ppg->m_uVScrollCode=0xFFFF;
ppg->m_uHScrollCode=0xFFFF;
m_fPendingRepaint=FALSE;
pt.x-=m_ptPick.x;
pt.y-=m_ptPick.y;
m_ptLast=pt;
m_fFeedback=TRUE;
ppg->DrawDropTargetRect(&pt, &m_szl);
return NOERROR;
}
/*
* CDropTarget::DragOver
*
* Purpose:
* Indicates that the mouse was moved inside the window represented
* by this drop target. This happens on every WM_MOUSEMOVE, so this
* function should be very efficient.
*
* Parameters:
* grfKeyState DWORD providing the current keyboard and mouse states
* pt POINTL where the mouse currently is.
* pdwEffect LPDWORD in which to store the effect flag for this point.
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
, LPDWORD pdwEffect)
{
LPCPages ppg=m_pDoc->m_pPG;
UINT uRet, uLast;
UINT xPos, yPos;
if (NULL==m_pIDataObject)
return NOERROR;
//Check if this is still a valid point. uRet is used below as well.
uRet=ppg->UTestDroppablePoint(&pt);
if (UDROP_NONE==uRet)
*pdwEffect=DROPEFFECT_NONE;
else
{
//Store these before possibly ORing in DROPEFFECT_SCROLL
*pdwEffect=DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL)
*pdwEffect=DROPEFFECT_COPY;
}
//If we haven't moved and we are not scrolling, then we're done.
if ((pt.x-m_ptPick.x==m_ptLast.x) && (pt.y-m_ptPick.y==m_ptLast.y)
&& !((UDROP_INSETHORZ | UDROP_INSETVERT) & ppg->m_uLastTest))
{
return NOERROR;
}
//Remove the last feedback rectangle.
if (m_fFeedback)
ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
uLast=ppg->m_uLastTest;
ppg->m_uLastTest=uRet;
if (UDROP_NONE==uRet)
{
//If we are now an invalid point, better repaint as necessary
if (m_fPendingRepaint)
{
UpdateWindow(ppg->m_hWnd);
m_fPendingRepaint=FALSE;
}
ppg->m_uVScrollCode=0xFFFF;
ppg->m_uHScrollCode=0xFFFF;
m_fFeedback=FALSE;
return NOERROR;
}
/*
* Scrolling is a little tricky: We get a DragOver pulse even
* if we didn't move. First we have to delay scrolling for
* ppg->m_uScrollDelay clock ticks which we can determine using
* GetTickCount. Timers do not work here since we may not be
* yielding to our message loop.
*
* Once we know we are scrolling then we determine if we
* scroll again or if we reset the scrolling state.
*/
if ((UDROP_INSETHORZ & uLast) && !(UDROP_INSETHORZ & uRet))
ppg->m_uHScrollCode=0xFFFF;
if (!(UDROP_INSETHORZ & uLast) && (UDROP_INSETHORZ & uRet))
{
ppg->m_dwTimeLast=GetTickCount();
ppg->m_uHScrollCode=(0!=(UDROP_INSETLEFT & uRet))
? SB_LINELEFT : SB_LINERIGHT; //Same as UP & DOWN codes.
}
if ((UDROP_INSETVERT & uLast) && !(UDROP_INSETVERT & uRet))
ppg->m_uVScrollCode=0xFFFF;
if (!(UDROP_INSETVERT & uLast) && (UDROP_INSETVERT & uRet))
{
ppg->m_dwTimeLast=GetTickCount();
ppg->m_uVScrollCode=(0!=(UDROP_INSETTOP & uRet))
? SB_LINEUP : SB_LINEDOWN;
}
if (0xFFFF==ppg->m_uHScrollCode && 0xFFFF==ppg->m_uVScrollCode)
ppg->m_dwTimeLast=0L;
//Set the scroll effect on any inset hit.
if ((UDROP_INSETHORZ | UDROP_INSETVERT) & uRet)
*pdwEffect |= DROPEFFECT_SCROLL;
xPos=ppg->m_xPos;
yPos=ppg->m_yPos;
//Has the delay elapsed? We can scroll if so
if (ppg->m_dwTimeLast!=0
&& (GetTickCount()-ppg->m_dwTimeLast) > (DWORD)ppg->m_uScrollDelay)
{
if (0xFFFF!=ppg->m_uHScrollCode)
{
m_fPendingRepaint=TRUE;
SendMessage(ppg->m_hWnd, WM_HSCROLL, ppg->m_uHScrollCode, 0L);
}
if (0xFFFF!=ppg->m_uVScrollCode)
{
m_fPendingRepaint=TRUE;
SendMessage(ppg->m_hWnd, WM_VSCROLL, ppg->m_uVScrollCode, 0L);
}
}
//If we didn't scroll anywhere by have a pending repaint, do it now.
if (xPos==ppg->m_xPos && yPos==ppg->m_yPos && m_fPendingRepaint)
{
UpdateWindow(ppg->m_hWnd);
m_fPendingRepaint=FALSE;
}
pt.x-=m_ptPick.x;
pt.y-=m_ptPick.y;
m_ptLast=pt;
m_fFeedback=TRUE;
ppg->DrawDropTargetRect(&pt, &m_szl);
return NOERROR;
}
/*
* CDropTarget::DragLeave
*
* Purpose:
* Informs the drop target that the operation has left its window.
*
* Parameters:
* None
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::DragLeave(void)
{
LPCPages ppg=m_pDoc->m_pPG;
if (NULL==m_pIDataObject)
return NOERROR;
//Stop scrolling
ppg->m_uHScrollCode=0xFFFF;
ppg->m_uVScrollCode=0xFFFF;
if (m_fPendingRepaint)
UpdateWindow(ppg->m_hWnd);
//Remove the last feedback rectangle.
if (m_fFeedback)
ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
m_fFeedback=FALSE;
m_pIDataObject->Release();
return NOERROR;
}
/*
* CDropTarget::Drop
*
* Purpose:
* Instructs the drop target to paste the data that was just now dropped
* on it.
*
* Parameters:
* pIDataSource LPDATAOBJECT from which we'll paste.
* grfKeyState DWORD providing current keyboard/mouse state.
* pt POINTL at which the drop occurred.
* pdwEffect LPDWORD in which to store what you do with the data.
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
LPCPages ppg=m_pDoc->m_pPG;
BOOL fRet=TRUE;
FORMATETC fe;
TENANTTYPE tType;
PATRONOBJECT po;
POINT ptS;
*pdwEffect=DROPEFFECT_NONE;
if (NULL==m_pIDataObject)
return ResultFromScode(E_FAIL);
if (UDROP_NONE==ppg->UTestDroppablePoint(&pt))
return ResultFromScode(E_FAIL);
//Stop scrolling
ppg->m_uHScrollCode=0xFFFF;
ppg->m_uVScrollCode=0xFFFF;
if (m_fPendingRepaint)
UpdateWindow(ppg->m_hWnd);
//2. Remove the UI feedback
if (m_fFeedback)
ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
m_pIDataObject->Release();
/*
* Check if we can do the paste, and if so, tell our pasting
* mechanism exactly where to place us.
*/
pt.x-=m_ptPick.x;
pt.y-=m_ptPick.y;
POINTFROMPOINTL(ptS, pt);
ScreenToClient(ppg->Window(), &ptS);
POINTLFROMPOINT(po.ptl, ptS);
//This condition is true if we didn't see placement data in DragEnter
if (0!=m_fe.cfFormat)
{
po.szl.cx=m_szl.cx; //We stored these positive
po.szl.cy=-m_szl.cy;
}
else
SETSIZEL(po.szl, 0, 0); //Ask object for its size.
//Adjust for scrolling and mapping mode.
ppg->AdjustPosition(&po.ptl, &po.szl);
/*
* If we're in the same document and moving, then we can just
* stuff the Pages' m_ptDrop which will move us and return.
*/
if (ppg->m_fDragSource && !(grfKeyState & MK_CONTROL))
{
*pdwEffect=DROPEFFECT_MOVE;
ppg->m_fMoveInPage=TRUE;
ppg->m_ptDrop=po.ptl;
return NOERROR;
}
/*
* Otherwise, paste either from another document or from
* the same document which will always be a copy to the new point.
*/
ppg->m_fMoveInPage=FALSE;
fRet=m_pDoc->FQueryPasteFromData(pIDataSource, &fe, &tType);
if (fRet)
{
//Copy the real format if we have placement data.
po.fe=(m_pDoc->m_cf==fe.cfFormat) ? m_fe : fe;
fRet=m_pDoc->FPasteFromData(pIDataSource, &fe, tType, &po, 0);
}
if (!fRet)
return ResultFromScode(E_FAIL);
*pdwEffect=DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL)
*pdwEffect=DROPEFFECT_COPY;
return NOERROR;
}